import numpy as np

# 假设数据（每行代表一个样本，每列代表一个指标）
data = np.array([
    [80, 70, 60, 75],
    [70, 85, 70, 80],
    [90, 75, 80, 90],
    [85, 80, 65, 85],
    [56, 75, 10, 96],
    [10, 69, 40, 25]
])


# 数据标准化（最小-最大标准化，只除以最大值）
def standardize(data):
    max_vals = data.max(axis=0)
    standardized_data = data / max_vals
    return standardized_data


# 计算信息熵
def calculate_entropy(data):
    n_samples, n_features = data.shape
    epsilon = 1e-10  # 避免log(0)的情况
    p = data / data.sum(axis=0, keepdims=True)
    p = np.clip(p, epsilon, 1 - epsilon)  # 将概率值限制在[epsilon, 1-epsilon]范围内
    entropy = -np.sum(p * np.log(p), axis=0) / np.log(n_samples)
    return entropy


# 计算权重（基于冗余度）
def calculate_weights(redundancy):
    return redundancy / redundancy.sum()


# 计算社会承压指数（SPI）的原始值（已经是0-1范围，不需要额外映射）
def calculate_spi(standardized_data, weights):
    return np.dot(standardized_data.mean(axis=0), weights) * 100  # 乘以100是为了得到0-100范围的SPI值（尽管已经是0-1标准化了）


# 但由于我们已经是0-1标准化，实际上不需要再乘以100，除非有特定要求
# 如果不需要0-100范围，可以直接返回 np.dot(standardized_data.mean(axis=0), weights)

# 主函数
def main():
    # 标准化数据
    standardized_data = standardize(data)

    # 由于标准化后的数据直接用于计算权重可能会导致数值问题（如除以0），
    # 我们通常会对标准化后的数据加一个非常小的数（如epsilon）来避免这种情况。
    # 但在本例中，由于数据已经是整数且经过标准化，我们假设不会出现除以0的情况。
    # 如果在实际应用中遇到数值稳定性问题，应该加上epsilon。

    # 但为了演示目的，并且知道我们的数据不会造成除以0的情况，我们直接计算信息熵。
    # 注意：在实际应用中，如果标准化后的数据中有0值，应该在使用之前先加上一个小的正数（epsilon）。

    # 计算信息熵
    entropy = calculate_entropy(standardized_data)
    # 注意：这里的calculate_entropy函数可能不适用于已经标准化的数据，
    # 因为标准化后的数据不再表示原始数据的概率分布。
    # 在实际应用中，我们应该在标准化之前计算信息熵，或者使用其他方法来确定权重。
    # 但为了与您的要求保持一致，并且仅作为演示目的，我们继续使用这个函数。
    # 请注意，这种方法在理论上是不正确的，但在没有更多信息的情况下，我们暂时采用它。

    # 由于上述原因，下面的冗余度和权重的计算也是基于一个不太严谨的方法。
    # 在实际应用中，应该采用更合适的方法来确定权重。

    # 计算冗余度（这里只是为了演示，实际上这种方法可能不准确）
    redundancy = 1 - entropy

    # 计算权重（这里只是为了演示，实际上这种方法可能不准确）
    weights = calculate_weights(redundancy)

    # 计算社会承压指数（SPI）
    # 由于我们的数据已经是0-1标准化，并且我们想要得到一个0-100范围的SPI值，
    # 我们将SPI的原始值乘以100。但请注意，这仅仅是为了满足特定的输出范围要求。
    # 如果不需要0-100范围，可以直接计算SPI的原始值。
    spi = calculate_spi(standardized_data, weights)

    # 输出结果
    print("标准化数据：\n", standardized_data)
    # 注意：由于calculate_entropy函数不适用于已经标准化的数据，
    # 下面的信息熵、冗余度和权重的输出仅供演示，并不准确。
    print("信息熵（注意：可能不准确）：\n", entropy)
    print("冗余度（注意：可能不准确）：\n", redundancy)
    print("权重（注意：可能不准确）：\n", weights)
    print("社会承压指数（SPI，0-100范围）：", spi)


if __name__ == "__main__":
    main()